package com.broada.apm.protocol;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;

import com.broada.apm.common.util.XmlUtil;
import com.broada.apm.model.DictMetrics;
import com.broada.apm.model.Dimension;
import com.broada.apm.model.Dimension.Error;
import com.broada.apm.model.L7ModuelPanel;
import com.broada.apm.model.L7Module;
import com.broada.apm.model.L7moduleMenu;
import com.broada.apm.model.L7moduleMenuitem;
import com.broada.apm.model.L7moduleMetric;
import com.broada.apm.util.Constants.Status;
import com.broada.apm.utils.JsonUtil;

public class L7ModuleParser {
    private static Map<String,Integer> alogithmMap = new HashMap<String,Integer>();

    static {
        alogithmMap.put("avg", DictMetrics.OPERATOR_AVG);
        alogithmMap.put("sum", DictMetrics.OPERATOR_SUM);
        alogithmMap.put("min", DictMetrics.OPERATOR_MIN);
        alogithmMap.put("max", DictMetrics.OPERATOR_MAX);
        alogithmMap.put("stdev", DictMetrics.OPERATOR_STDEV);
    }
    public static class L7ModuleDescr {
        String metricBase;
        L7Module module = new L7Module();
        List<L7moduleMetric> metrics = new ArrayList<L7moduleMetric>();
        List<L7ModuelPanel> panels = new ArrayList<L7ModuelPanel>();
        List<Dimension.Error> errortable = new ArrayList<Dimension.Error>();
        List<L7moduleMenu> menus = new ArrayList<L7moduleMenu>();
        public String getMetricBase() {
            return metricBase;
        }
        public L7Module getModule() {
            return module;
        }
        public List<L7moduleMetric> getMetrics() {
            return metrics;
        }
        public List<L7ModuelPanel> getPanels() {
            return panels;
        }
        public List<Dimension.Error> getErrortable() {
            return errortable;
        }
        public List<L7moduleMenu> getMenus() {
            return menus;
        }
        
    }
    public static L7ModuleDescr fastParse(String fileName) throws JDOMException, IOException {
        return doParse(fileName, false);
    }
    public static L7ModuleDescr parse(String fileName) throws JDOMException, IOException{
        return doParse(fileName,true);
    }
    private static L7ModuleDescr doParse(String fileName,boolean all) throws JDOMException, IOException {
        L7ModuleDescr l7ModuleDescr = new L7ModuleDescr();
        Document doc = XmlUtil.getDoc(fileName);
        Element rootNode = doc.getRootElement();
        String id = rootNode.getAttributeValue("id");
        String l7_proto = rootNode.getAttributeValue("l7_proto");
        String name = rootNode.getAttributeValue("name");
        name = name != null ? name.toUpperCase() : null;
        String cname = rootNode.getAttributeValue("cname");
        cname = cname != null ? cname.toUpperCase() : null;
        String version = rootNode.getAttributeValue("version");
        String compatible = rootNode.getAttributeValue("compatible");
        String type = rootNode.getAttributeValue("type");
        String proto = rootNode.getAttributeValue("proto");
        String category = rootNode.getAttributeValue("category");
        String analyzer_version = null;
        String logo = null;
        String _fileName = null;
        String memo = null;
        String lang = null;
        String java = null;
        List<Element> elementList = rootNode.getChildren();
        // 遍历配置文件
        for (int i = 0; i < elementList.size(); i++) {
            Element child = (Element) elementList.get(i);
            if ("analyzer_version".equals(child.getName()))
                analyzer_version = child.getText();
            if ("lang".equals(child.getName()))
                lang = child.getText();
            if ("proto".equals(child.getName()))
                proto = child.getText();
            if ("logo".equals(child.getName()))
                logo = child.getText();
            if ("category".equals(child.getName()))
                category = child.getText();
            if ("filename".equals(child.getName()))
                _fileName = child.getText();
            if ("memo".equals(child.getName()))
                memo = child.getText();
            if ("java".equals(child.getName()))
                java = child.getText();
            if (all && "errortable".equals(child.getName()))
                parserErrorTable(l7ModuleDescr, l7_proto, child);
            if(all && "metrics".equals(child.getName())) {
                parseMetrics(l7ModuleDescr, id, child);
            }
            if(all && "panels".equals(child.getName())) {
                parsePanels(l7ModuleDescr, id, child);
            }
            if(all && "menus".equals(child.getName())) {
                parseMenu(l7ModuleDescr, id, child);
            }
        }
        // 默认不启用状态
        L7Module module = new L7Module();
        module.setId(id);
        module.setBaseId(l7ModuleDescr.metricBase);
        module.setL7_proto(Integer.parseInt(l7_proto));
        module.setName(name);
        module.setCname(cname);
        module.setVersion(version);
        module.setCompatible(compatible);
        module.setType(type);
        module.setLang(lang);
        module.setProto(proto);
        module.setCategory(category);
        module.setAnalyzer_version(analyzer_version);
        module.setLogo(logo);
        module.setFileName(_fileName);
        module.setMemo(memo);
        module.setJava(java);
        module.setStatus(Status.DISABLED.getVallue());
         
        l7ModuleDescr.module = module;
        return l7ModuleDescr;
    }
    private static void parseMenu(L7ModuleDescr l7ModuleDescr, String moduleId, Element child) {
        @SuppressWarnings("unchecked")
        List<Element> menus = child.getChildren();
        for(int j = 0; j < menus.size(); j++) {
            Element menu = menus.get(j);
            L7moduleMenu l7moduleMenu = new L7moduleMenu();
            l7moduleMenu.setModuleId(moduleId);
            l7moduleMenu.setCaption(menu.getAttributeValue("name"));
            l7moduleMenu.setFieldGroupby(menu.getAttributeValue("field"));
            l7moduleMenu.setFieldWhere(menu.getAttributeValue("where"));
            String visible = menu.getAttributeValue("visible");
            l7moduleMenu.setVisibility("true".equals(visible)?1 : 0);
            l7moduleMenu.setDisplayOrder(j);
            
            l7ModuleDescr.menus.add(l7moduleMenu);
            
            @SuppressWarnings("unchecked")
            List<Element> items = menu.getChildren();
            for(int k = 0; k < items.size(); k++) {
                Element item = items.get(k);
                L7moduleMenuitem menuItem = new L7moduleMenuitem();
                String itemCaption = item.getAttributeValue("name");
                String itemField = item.getAttributeValue("field");
                String mappingClass = item.getAttributeValue("mapping_class");
                String metric = item.getAttributeValue("metric");
                menuItem.setMetricCode(metric);
                
                String openmenu = item.getChildTextTrim("openmenu");
                menuItem.setOpenMenuName(openmenu);
                
                menuItem.setMenuName(l7moduleMenu.getCaption());
                menuItem.setItemCaption(itemCaption);
                menuItem.setFieldName(itemField);
                menuItem.setMappingClass(mappingClass);
                menuItem.setItemIndex(k);
                menuItem.setWidth(item.getChildTextTrim("width"));
                menuItem.setAlign(item.getChildTextTrim("align"));
                menuItem.setTransform(item.getChildTextTrim("transform"));
                menuItem.setSort(item.getAttributeValue("sort"));
                l7moduleMenu.getMenuItems().add(menuItem);
            }
        }
    }
    private static void parsePanels(L7ModuleDescr l7ModuleDescr, String moduleId, Element child) {
    	
        @SuppressWarnings("unchecked")
        List<Element> panelList = child.getChildren();
        for(int i = 0; i < panelList.size(); i++) {
            Element panels = panelList.get(i);
            String panelId = panels.getAttributeValue("id");
            
	        @SuppressWarnings("unchecked")
	        List<Element> grids = panels.getChildren();
	        for(int j = 0; j < grids.size(); j++) {
	            Element grid = grids.get(j);
	            L7ModuelPanel panel = new L7ModuelPanel();
	            
	            panel.setPanelId(panelId);
	            String gridId = grid.getAttributeValue("id");
	            panel.setPanelIndex(Integer.parseInt(gridId));
	            String code = grid.getChildText("code");
	            panel.setMetricCode(code);
	            panel.setMetricCaption(grid.getChildText("caption"));
	            panel.setTransform(grid.getChildTextTrim("transform"));
	            String display = grid.getChildText("display");
	            if(display != null && display.endsWith("60")) {
	                panel.setDisplayWay(2);
	            } else {
	                panel.setDisplayWay(1);
	            }
	            l7ModuleDescr.panels.add(panel);
	            panel.setModuleId(moduleId);
	        }
        }
    }
    private static void parseMetrics(L7ModuleDescr l7ModuleDescr, String moduleId, Element child) {
        String base = child.getAttributeValue("base");
        l7ModuleDescr.metricBase = base;
        @SuppressWarnings("unchecked")
        List<Element> metric1s = child.getChildren();
        for(int j = 0; j < metric1s.size(); j++) {
            Element metric1 = metric1s.get(j);
            if("metric".equals(metric1.getName()))
                //当前metric为第一层无parentId,注L7Module还未保存，如database有外键需调整保存顺序(暂不改动)
                metricChild(l7ModuleDescr, metric1, moduleId);
        }
    }
    private static void parserErrorTable(L7ModuleDescr l7ModuleDescr, String l7_proto, Element child) {
        {
            List<Element> errortable = child.getChildren();
            for (int j = 0; j < errortable.size(); j++) {
                Element error = (Element) errortable.get(j);
                String errorCode = error.getAttributeValue("code");
                String status = error.getAttributeValue("status","0");
                String value = error.getValue().trim();
                Error _error = new Error();
                _error.setId(l7_proto + "." + errorCode);
                _error.setCode(errorCode);
                _error.setErrorMessage(value);
                _error.setProtocol(Integer.valueOf(l7_proto));
                _error.setStatus(Integer.parseInt(status));
                l7ModuleDescr.errortable.add(_error);
            }
        }
    }

    private static void metricChild(L7ModuleDescr l7ModuleDescr, Element metric, String moduleId) {
        L7moduleMetric dictMetrics = new L7moduleMetric();
    	
    	String code = metric.getAttributeValue("code");
    	String name = metric.getAttributeValue("name");
    	String transform = metric.getAttributeValue("transform");
    	
    	dictMetrics.setCode(code);
    	dictMetrics.setName(name);
    	dictMetrics.setTransform(transform);
    	dictMetrics.setModuleId(moduleId);
    	dictMetrics.setLayer(code.split("/").length);
    	
    	String valid = metric.getChildText("valid");
    	if(valid != null) {
    		String[] vstr = valid.split(",");
    		for(String v : vstr) {
    			if("app".equals(v)) 
    				dictMetrics.setAppValid(true);
    			if("node".equals(v))
    				dictMetrics.setNodeValid(true);
    			if("transaction".equals(v))
    				dictMetrics.setTransValid(true);
    			if("domain".equals(v))
    				dictMetrics.setDomainValid(true);
    		}
    	}
    	
    	String chart = metric.getAttributeValue("chart");
    	dictMetrics.setChart(chart);
    	String main = metric.getAttributeValue("main");
    	if("y".equals(main)) {
    		dictMetrics.setMain(1);
    	} else {
    		dictMetrics.setMain(0);
    	}
    	
    	String alogithm = metric.getChildText("alogithm");
    	if(alogithm != null) {
    		Integer alogithmValue = alogithmMap.get(alogithm);
    		dictMetrics.setCollectionAlogithm(alogithmValue==null?0 : alogithmValue);
    	}
    	
    	String memo = metric.getChildText("memo");
    	if(memo != null)
    		dictMetrics.setMemo(memo);
    	
    	String caption = metric.getChildText("caption");
    	if(caption != null) {
    	    dictMetrics.setCode(code);
    	    dictMetrics.setName(name);
    	    dictMetrics.setMetricCaption(caption);
    	    dictMetrics.setDisplayOrder(metric.getParentElement().getContent().indexOf(metric));
    	}
    	
    	l7ModuleDescr.metrics.add(dictMetrics);
    	
    	@SuppressWarnings("unchecked")
    	List<Element> metricChild = metric.getChildren("metric");
    	for(Element mc : metricChild) {
    		metricChild(l7ModuleDescr, mc, moduleId);//解析子节点Metric
    	}
    }
    public static void main(String[] args) throws JDOMException, IOException {
        L7ModuleDescr module = L7ModuleParser.parse("C:\\prod\\apm\\trunk\\apm_r2\\analyze\\protocol_analyzer\\conf\\modules\\80\\module.xml");
        System.out.println(JsonUtil.obj2json(module));
        
    }
}
